/*-------------------------------------------------------------*\
0: reg    pp   ; acc=pp
1: output pp   ; o_portid = pp, o_port = ram[pp] 
2: input  pp   ; o_portid = pp, ram[pp] = i_port
3: ldr    pp   ; ram[acc] = ram[pp]
4: ldi    dd   ; ram[acc] = dd 
5: add    pp   ; ram[acc] = ram[acc] + ram[pp]
6: sub    pp   ; ram[acc] = ram[acc] - ram[pp]
7: and    pp   ; ram[acc] = ram[acc] & ram[pp]
8: or     pp   ; ram[acc] = ram[acc] | ram[pp]
9: sl     pp   ; ram[pp]    = ram[pp] << 1
a: sr     pp   ; ram[pp]    = ram[pp] >> 1
b: jmp    pp   ; pc = pp   
c: jmpz   pp   ; ram[acc]==0 ? pc=pp : pc = pc+1
\*-------------------------------------------------------------*/

`include "cbb_rom.v"
`include "cbb_dpram_2.v"

module meu #(
    parameter ROM_FILE = "",
    parameter ROM_NUM = 0,
    parameter RAM_SIZE = 256
)(
    input clk ,
    input rst_n ,
    input [7:0]i_port ,
    output  [7:0]o_port ,
    output reg o_wen ,
    output  [7:0]o_portid 
);

reg [7:0] a = 8'h00;
reg [7:0] b = 8'h00; 
reg [7:0] pc= 8'h00;
wire [7:0] address_a , address_b ;
wire [7:0] data_a ;
wire [7:0] q_a , q_b ;
reg wren_a ;

wire [11:0]instr ;

wire [3:0] opcode = instr[11:8] ;
wire [7:0] pp     = instr[7:0] ;
reg [7:0] acc = 8'h00;
reg [1:0] jp = 2'b01;

wire [7:0] pc_next ;
wire [7:0] acc_next ;

assign acc_next = (opcode == 4'h0) ? pp : acc ;

assign address_a = ( (opcode>4'h2 && opcode <4'h9) || (opcode==4'hc)) ? acc : pp ;
// assign address_a = (  (opcode==4'h2)||(opcode==4'h9) || (opcode==4'ha) ) ? pp : acc_next ;
assign address_b = pp ;

assign o_portid = pp;
assign o_port   = q_a ;

assign pc_next = ((opcode == 4'hb) || ((opcode==4'hc) &&(~|q_a) )) ? pp :
                 pc + 1'b1 ;

assign data_a = (opcode == 4'h2) ? i_port :
                (opcode == 4'h3) ? q_b :
                (opcode == 4'h4) ? pp :
                (opcode == 4'h5) ? q_a + q_b :
                (opcode == 4'h6) ? q_a - q_b :
                (opcode == 4'h7) ? q_a & q_b :
                (opcode == 4'h8) ? q_a | q_b :
                (opcode == 4'h9) ? q_a << 1 :
                (opcode == 4'ha) ? q_a >> 1 :
                8'h00 ;

always@(posedge clk) begin
    wren_a <= 1'b0 ;
    o_wen <= 1'b0 ;
    if(~rst_n) begin
        pc <= 8'h00;
        jp <= 2'b01;
        acc <= 8'h00;
    end else begin
        jp <= {jp[0] , jp[1]} ;
        if(jp[1]) begin
            pc <= pc_next ;
            // 执行 
            if(opcode >=4'h2 && opcode <4'hb) begin
                wren_a <= 1'b1 ;
            end

            if(opcode == 4'h0) begin
                acc <= pp;
            end

            if(opcode == 4'h1) begin
                o_wen <= 1'b1;
            end
        end
    end
end

cbb_dpram_2 #(
    .DATA_DEPTH    ( RAM_SIZE ) ,  // 数据深度 ， 存的数据个数
    .DATA_WIDTH    ( 8    ),  // 数据位宽
    .ADDR_WIDTH    ( 8    ),  // 地址位宽
    .ENABLE_ASYNC  ( 0    )   // 是否设置输出异步 1：EDA会使用逻辑单元模拟  0: eda大概率会调用memory
) eu_ram (
	.address_a ( address_a) ,
	.address_b ( address_b) ,
	.clock     ( clk) ,
	.data_a    ( data_a) ,
	.data_b    ( 8'h00) ,
	.wren_a    ( wren_a) ,  // 高电平时写数据
	.wren_b    ( 1'b0) ,
	.q_a       ( q_a) ,
	.q_b       ( q_b) 
) ;


cbb_rom #(
    .MEM_FILE(ROM_FILE),  // ROM初始化文件 
    .MEM_NUM(ROM_NUM) ,// ROM存储的数量
    .DATA_WIDTH(12) , //数据位宽
    .ENABLE_ASYNC(0)  // 是否异步于时钟输出
) eu_rom (
    .clk( clk) , 
    .address(pc[$clog2(ROM_NUM-1)-1 :0 ]),
    .data_out(instr) 
);



endmodule 